<!DOCTYPE html>
<html lang="en">
	<head>
	  <meta charset="UTF-8">
	  <meta name="viewport" content="width=device-width, initial-scale=1.0">
	  <meta http-equiv="X-UA-Compatible" content="ie=edge">
	  <title>Document</title>
	</head>
	<body>
		<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
		<script>
			// console.log(Object.is('foo','foo'))//true
			// console.log(Object.is({},{}));//false

			// console.log(+0 === -0);//true
			// console.log(NaN === NaN);//false

			// console.log(Object.is(+0,-0));//false
			// console.log(Object.is(NaN,NaN));//true

			// Object.defineProperty(Object,'is',{
			// 	value:function(x,y){
			// 		if(x === y){
			// 			return x !==0 || 1/x === 1/y;
			// 		}
			// 		return x !==x && y !==y;
			// 	},
			// 	configurable:true,
			// 	enumberable:false,
			// 	writbale:true
			// });

			// const target = { a: 1 };
			// const source1 = { b: 2 };
			// const source2 = { c: 3 };
			// Object.assign(target, source1, source2);
			// console.log(target);//{a: 1, b: 2, c: 3}

			// const target = { a:1,b:1 };
			// const source1 = { b:2,c:2 };
			// const source2 = { c:3 };
			// Object.assign(target,source1,source2);
			// console.log(target);//{a: 1, b: 2, c: 3}

			// const obj = { a:1 };
			// console.log(Object.assign(obj) === obj);//true

			// console.log(typeof Object.assign(2));//object

			// console.log(Object.assign(undefined));//Uncaught TypeError: Cannot convert undefined or null to object
			// console.log(Object.assign(null));//Uncaught TypeError: Cannot convert undefined or null to object

			//undefined和null不在首参数，就不会报错
			// let obj = {a:1};
			// console.log(Object.assign(obj,undefined)=== obj);//true
			// console.log(Object.assign(obj,null) === obj);//true


			// 除了字符串会以数组形式，拷贝入目标对象，其他值都不会产生效果
			// const v1 ='abc';
			// const v2 =true;
			// const v3 = 10;
			// const obj = Object.assign({},v1,v2,v3);
			// console.log(obj);//// { "0": "a", "1": "b", "2": "c" }

			// console.log(Object(true));// {[[PrimitiveValue]]: true}
			// console.log(Object(10))//  {[[PrimitiveValue]]: 10}
			// console.log(Object('abc'))// {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}

			// console.log(Object.assign({b:'c'},Object.defineProperty({},'invisible',{
			// 	enumberable:false,
			// 	value:'hello'
			// })));/{b: "c"}

			// console.log(Object.assign({a:'b'},{[Symbol('c')]:'d'}));//{a: "b", Symbol(c): "d"}

			// const obj1 = {a:{b:1}};
			// const obj2 = Object.assign({},obj1);
			// obj1.a.b = 2;
			// console.log(obj2.a.b);//2

			// const target = {a:{b:'c',d:'e'}};
			// const source = {a:{b:'hello'}};
			// console.log(Object.assign(target,source));// { a: { b: 'hello' } }

			// console.log(Object.assign([1,2,3],[4,5]));//[4, 5, 3]

			// const source = {
			// 	get foo(){return 1}
			// };
			// const target = {};
			// console.log(Object.assign(target,source));//{foo: 1}


			//通过Object.assign方法，将x属性和y属性添加到Point类的对象实例
			// class Point {
			//   constructor(x, y) {
			//     Object.assign(this, {x, y});
			//   }
			// }

			// 将两个函数放在大括号中，再使用assign方法添加到SomeClass.prototype之中
			// Object.assign(SomeClass.prototype,{someMethod(arg1,arg2){
			// 		...
			// 	},
			// 	antherMethod(){
			// 		...
			// 	}
			// });
			// // 等同于下面的写法
			// SomeClass.prototype.someMethod = function(arg1,arg2){
			// 	...
			// }
			// SomeClass.prototype.antherMethod = function(){
			// 	...
			// }

			// 克隆原始对象自身的值,不能克隆它继承的值
			// function clone(origin){
			// 	return Object.assign({},origin);
			// }
			// 保持继承链
			// function clone(origin){
			// 	let originProto = Object.getPrototypeOf(origin);
			// 	return Object.assign(Object.create(originProto),origin);
			// }

			//将多个对象合并到某个对象
			// const merge = (target,...source) => Object.assign(target,...source);
			//合并后返回一个新对象，可以改写上面函数，对一个空对象合并
			// const merge = (...source) => Object.assign({},...source);


			// Object.assign方法将DEFAULTS和options合并成一个新对象，如果两者有同名属性，则options的属性值会覆盖DEFAULTS的属性值
			// const DEFAULTS = {
			// 	logLevel:0,
			// 	outputFormat:'html'
			// }
			// function processContent(options){
			// 	options = Object.assign({},DEFAULTS,options);
			// 	console.log(options);

			// }

			// 原意是将url.port改成 8000，url.host不变。实际结果却是options.url覆盖掉DEFAULTS.url，所以url.host就不存在了
			// const DEFAULTS = {
			// 	url:{
			// 		host:'example.com',
			// 		port:7070
			// 	}
			// };
			// processContent({ url: {port: 8000} })

			// const obj = {
			// 	foo:123,
			// 	get bar(){
			// 		return 'abc'
			// 	}
			// };
			// console.log(Object.getOwnPropertyDescriptors(obj));
			// { foo:
			//    { value: 123,
			//      writable: true,
			//      enumerable: true,
			//      configurable: true },
			//   bar:
			//    { get: [Function: get bar],
			//      set: undefined,
			//      enumerable: true,
			//      configurable: true } }

			// function getOwnPropertyDescriptors(obj){
			// 	const result ={};
			// 	for(let key of Reflect.owmKeys(obj)){
			// 		result[key] = Object.getOwnPropertyDescriptors(obj,key);
			// 	}
			// 	return result;
			// }

			// const source = {
			// 	set foo(value){
			// 		console.log(value);
			// 	}
			// };
			// const target1 = {};
			// Object.assign(target1,source);
			// console.log(Object.getOwnPropertyDescriptors(target1,'foo'));
			// { value: undefined,
			//   writable: true,
			//   enumerable: true,
			//   configurable: true }

			// const source = {
			//     set foo(value) {
			//     console.log(value);
			//   }
			// };
			// const target2 = {};
			// Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
			// console.log(Object.getOwnPropertyDescriptor(target2, 'foo'))
			// { get: undefined,
			//   set: [Function: set foo],
			//   enumerable: true,
			//   configurable: true }

			// function getOwnPropertyDescriptors(obj){
			// 	const result = {};
			// 	for(let key of Reflect.owmKeys(obj)){
			// 		result[key] = Object.getOwnPropertyDescriptor(obj,key);
			// 	}
			// 	return result;
			// }

			// const source = {
			// 	set foo(value){
			// 		console.log(value);
			// 	}
			// };
			// const target1 = {};
			// Object.assign(target1,source);
			// console.log(Object.getOwnPropertyDescriptor(target1,'foo'));
			// { value: undefined,
			//   writable: true,
			//   enumerable: true,
			//   configurable: true }

			// const source ={
			// 	set foo(value){
			// 		console.log(value);
			// 	}
			// };
			// const target2 = {};
			// Object.defineProperties(target2,Object.getOwnPropertyDescriptors(source));
			// console.log(Object.getOwnPropertyDescriptor(target2,'foo'));
			// { get: undefined,
			//   set: [Function: set foo],
			//   enumerable: true,
			//   configurable: true }

			// const shallowMerge = (target,source) => Object.defineProperties(target,Object.getOwnPropertyDescriptors(source));

			// const clone = Object.create(Object.getPrototypeOf(obj),
			// 	Object.getOwnPropertyDescriptors(obj));
			// 或者
			// const shallowClone = (obj) => Object.create(
			// 	Object.getPrototypeOf(obj),
			// 	Object.getOwnPropertyDescriptors(obj));

			//继承另一个对象
			// const obj ={
			// 	_proto_:prot,
			// 	foo:123,
			// }

			// 如果去除__proto__，上面代码就要改成下面这样
			// const obj = Object.create(prot);
			// obj.foo = 123;
			//或者
			// const obj = Object.assign(
			// 	Object.create(prot),
			// 	{
			// 		foo:123,
			// 	}
			// );


			// const obj = Object.create(
			// 	prot,
			// 	Object.getOwnPropertyDescriptors({
			// 		foo:123,
			// 		}
			// 	)
			// );

			// let mix = (object) => ({
			// 	with:(...mixins) => mixins.reduce(
			// 			(c,mixin) => Object.create(
			// 					c,Object.getOwnPropertyDescriptors(mixin)
			// 				),object
			// 		)
			// });
			// let a = {a:'a'};
			// let b = {b:'b'};
			// let c = {c:'c'};
			// let d = mix(c).with(a,b);
			// console.log(d.c);//c
			// console.log(d.b);//b
			// console.log(d.a);//a

			// es5 的写法
			// const obj = {
			// 	method:function(){...}
			// };
			// obj._proto_ = someOtherObj;

			// es6 的写法
			// var obj = Object.create(someOtherObj);
			// obj.method = function(){...};

			// Object.defineProperty(Object.prototype,'_proto_',{
			// 	get(){
			// 		let _thisObj = Object(this);
			// 		return Object.getPrototypeOf(_thisObj);
			// 	},
			// 	set(proto){
			// 		if(this === undefined || this === null
			// 			){
			// 			throw new TypeError();
			// 		}
			// 		if(!isObject(this)){
			// 			return undefined;
			// 		}
			// 		if(!isObject(proto)){
			// 			return undefined;
			// 		}
			// 		let status = Reflect.setPrototypeOf(this,proto);
			// 		if(!status){
			// 			throw new TypeError();
			// 		}
			// 	},
			// });
			// function isObject(value){
			// 	return Object(value) === value;
			// }

			// Object.getPrototypeOf({_proto_:null});//null

			// Object.setPrototypeOf(object,prototype)
			// const  o = Object.setPrototypeOf({},null);

			// function setPrototypeOf(obj,proto){
			// 	obj._proto_ = proto;
			// 	return obj;
			// }

			// let proto = {};
			// let obj ={x:10};
			// Object.setPrototypeOf(obj,proto);
			// proto.y = 20;
			// proto.z = 40;
			// console.log(obj.x);//10
			// console.log(obj.y);//20
			// console.log(obj.z);//40

			// console.log(Object.setPrototypeOf(1,{}) ===1);//true
			// console.log(Object.setPrototypeOf('foo',{}) ==='foo');//true
			// console.log(Object.setPrototypeOf(true,{}) ===true);//true

			// Object.setPrototypeOf(undefined,{});// TypeError: Object.setPrototypeOf called on null or undefined

			// Object.setPrototypeOf(null,{});// TypeError: Object.setPrototypeOf called on null or undefined

			// function Rectangle(){
			// 	// ...
			// }
			// const rec = new Rectangle();
			// console.log(Object.getPrototypeOf(rec) === Rectangle.prototype);//true

			// Object.setPrototypeOf(rec,Object.prototype);

			// console.log(Object.prototype);//constructor: ƒ Object()
			// console.log(Rectangle.prototypes);//constructor: ƒ Rectangle()
			// console.log(Object.getPrototypeOf(rec) === Rectangle.prototype);//false


			// console.log(Object.getPrototypeOf(1));// Number {[[PrimitiveValue]]: 0}
			// console.log(Object.getPrototypeOf('foo'));// String {length: 0, [[PrimitiveValue]]: ""}
			// console.log(Object.getPrototypeOf(true));// Boolean {[[PrimitiveValue]]: false}

			// console.log(Object.getPrototypeOf(1) ===Number.prototype);//true
			// console.log(Object.getPrototypeOf('foo') === String.prototype);//true
			// console.log(Object.getPrototypeOf(true) === Boolean.prototype);//true

			//参数是undefined或null，它们无法转为对象，所以会报错
			// console.log(Object.getPrototypeOf(null));// TypeError: Cannot convert undefined or null to object
			// console.log(Object.getPrototypeOf(undefined));// TypeError: Cannot convert undefined or null to object

			// var obj = {foo:'bar','baz':42};
			// console.log(Object.keys(obj));//["foo", "baz"]

			// let {keys,values,entries} = Object;
			// console.log(Object);//ƒ Object() { [native code] }
			// let obj = {a:1,b:2,c:3};
			// for(let key of keys(obj)){
			// 	console.log(key);//a b c
			// }
			// for (let value of values(obj)) {
			//     console.log(value); // 1, 2, 3
			// }
			// for(let [key,value] of entries(obj)){
			// 	console.log([key,value]);// ["a", 1] ["b", 2] ["c", 3]
			// }

			// const obj = {foo:'bar',baz:42};
			// console.log(Object.values(obj));//["bar", 42]

			//属性名为数值的属性，是按照数值大小，从小到大遍历的，因此返回的顺序是b、c、a
			// const obj = {100:'a',2:'b',7:'c'};
			// console.log(Object.values(obj));//["b", "c", "a"]

			// Object.create方法的第二个参数添加的对象属性（属性p），如果不显式声明，默认是不可遍历的，因为p的属性描述对象的enumerable默认是false
			// const obj = Object.create({},{p:{value:42}});
			// console.log(Object.values(obj));//[]

			// const obj = Object.create({},{p:{
			// 	value:42,
			// 	enumerable:true
			// }});
			// console.log(Object.values(obj));//[42]

			// Object.values会过滤属性名为 Symbol 值的属性
			// console.log(Object.values({[Symbol()]:123,foo:'abc'}));//["abc"]

			// console.log(Object.values('foo'));//["f", "o", "o"]
			// console.log(Object.values(42));//[]
			// console.log(Object.values(true));//[]

			// Object.entries只输出属性名非 Symbol 值的属性
			// const obj ={foo:'bar',baz:42};
			// console.log(Object.entries(obj));// [ ["foo", "bar"], ["baz", 42] ]

			// let obj = { one:1,two:2};
			// for(let [k,v] of Object.entries(obj)){
			// 	console.log(`${JSON.stringify(k)}:${JSON.stringify(v)}`
			// 		)
			// }
			//"one":1 "two":2

			// const obj ={ foo:'bar',baz:42};
			// const map =new Map(Object.entries(obj));
			// console.log(map);// Map { foo: "bar", baz: 42 }

			// 实现Object.entries方法
			// Generator函数的版本
			// function * entries(obj){
			// 	for(let key of Object.keys(obj)){
			// 		yield [key,obj[key]];
			// 	}
			// }
			// 非Generator函数的版本
			// function entries(obj){
			// 	let arr =[];
			// 	for(let key of Object.keys(obj)){
			// 		arr.push([key,obj[key]]);
			// 	}
			// 	return arr;
			// }


			// Object.fromEntries([
			//     ['foo', 'bar'],
			//     ['baz', 42]
			// ]);
			// console.log(Object);

			// const entries = new Map([
			// 	['foo','bar'],
			// 	['bar',42]
			// ]);
			// Object.fromEntries(entries);

			// const map = new Map().set('foo',true).set('bar',false);
			// Object.fromEntries(map);

			// Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'));






		</script>
	</body>
</html>